package com.wt.springsamples.security.listener;

import com.wt.springsamples.biz.service.ISysFunctionService;
import com.wt.springsamples.model.SysFunction;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.*;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class RefreshFunctionApplicationListener implements ApplicationListener<ContextRefreshedEvent>{

    @Autowired
    private ISysFunctionService sysFunctionService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        log.info("===========RefreshFunctionApplicationListener onApplicationEvent ===========");
        Map<String, Object> beansWithAnnotationApi = applicationContext.getBeansWithAnnotation(Api.class);
        List<SysFunction> funcList = new ArrayList<>();
        beansWithAnnotationApi.forEach((key,apiBean)->{
//            if(AopUtils.isAopProxy(apiBean)){
//                try {
//                    apiBean = ((Advised) apiBean).getTargetSource().getTarget();
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
//            Object targetObj = AopProxyUtils.getSingletonTarget(apiBean);
//            Class<?> controllerType = apiBean.getClass();
            Class<?> controllerType = AopUtils.getTargetClass(apiBean);
            Method[] declaredMethods = controllerType.getDeclaredMethods();
            RequestMapping declaredAnnotation = controllerType.getDeclaredAnnotation(RequestMapping.class);
            String prefix = declaredAnnotation==null?"":(declaredAnnotation.value().length>0?declaredAnnotation.value()[0]:"");
            for(Method method:declaredMethods){

                RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
                String subfix = requestMapping==null?"":(requestMapping.value().length>0?requestMapping.value()[0]:"");

//                ApiOperation  operationAnnotation = method.getDeclaredAnnotation(ApiOperation.class);
                ApiOperation  operationAnnotation  = AnnotatedElementUtils.findMergedAnnotation(method, ApiOperation.class);
                if(operationAnnotation==null){
                    continue;
                }
                String functionCode = operationAnnotation.value();
                String functionName = operationAnnotation.nickname();

                SysFunction sysFunction = new SysFunction();
                sysFunction.setCode(functionCode);
                sysFunction.setName(functionName);
                sysFunction.setPath(prefix.concat(subfix));
                funcList.add(sysFunction);
            }
        });

        List<SysFunction>  oldList = sysFunctionService.getAll();
        List<SysFunction>  newList = new ArrayList<>();
        for(SysFunction func:funcList){
            boolean exist = false;
            for(SysFunction old:oldList){
                if(StringUtils.hasText(func.getPath()) && func.getPath().equals(old.getPath())){
                    exist = true;
                    break;
                }
            }
            if(!exist){
                newList.add(func);
            }
        }
        if(!CollectionUtils.isEmpty(newList)){
            sysFunctionService.saveBatch(newList,newList.size());
        }
    }

    @EventListener
    @Async
    public void processBlockedListEvent(BlockedListEvent event) {
        // BlockedListEvent is processed in a separate thread
    }
}
